You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

70 lines
2.0 KiB

<script setup lang="ts">
import { unwrapApiBody, type ApiResponse } from '../../../utils/http/factory'
definePageMeta({
layout: 'public',
})
const route = useRoute()
const publicSlug = computed(() => route.params.publicSlug as string)
const postSlug = computed(() => route.params.postSlug as string)
type Post = {
title: string
slug: string
excerpt: string
bodyMarkdown: string
coverUrl: string | null
publishedAt: Date | null
}
const { data, pending, error } = await useAsyncData(
() => `public-post-${publicSlug.value}-${postSlug.value}`,
async () => {
const path = `/api/public/profile/${encodeURIComponent(publicSlug.value)}/posts/${encodeURIComponent(postSlug.value)}`
const res = await $fetch<ApiResponse<{ post: Post }>>(path)
return unwrapApiBody(res).post
},
{ watch: [publicSlug, postSlug] },
)
watchEffect(() => {
if (data.value?.title) {
useHead({ title: data.value.title })
}
})
</script>
<template>
<UContainer class="py-10 space-y-6">
<div v-if="pending" class="text-muted">
加载中…
</div>
<UAlert v-else-if="error" color="error" title="文章不存在或未公开" />
<template v-else-if="data">
<UButton :to="`/@${publicSlug}`" variant="ghost" color="neutral" size="sm" class="-ml-2">
← 返回主页
</UButton>
<div v-if="data.coverUrl" class="flex justify-center">
<img
:src="data.coverUrl"
alt=""
class="max-h-64 w-full max-w-2xl rounded-lg object-cover border border-default"
>
</div>
<p v-if="data.publishedAt" class="text-sm text-muted">
{{ data.publishedAt }}
</p>
<h1 class="text-2xl font-semibold">
{{ data.title }}
</h1>
<p v-if="data.excerpt" class="text-muted">
{{ data.excerpt }}
</p>
<article class="prose dark:prose-invert max-w-none whitespace-pre-wrap">
{{ data.bodyMarkdown }}
</article>
<PostComments mode="public-post" :public-slug="publicSlug" :post-slug="postSlug" />
</template>
</UContainer>
</template>